﻿/**
 * FFXIIRCGateway
 *
 * @package ffxiircgateway
 * @version $Id: Memory.cs 18 2009-03-17 05:13:49Z ayunyan $
 * @author ayunyan <ayu@commun.jp>
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
 * @link http://code.google.com/p/ffxiircgateway
 */
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;

namespace FFXIIRCGateway
{
    public class Memory
    {
        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, IntPtr lpSize, IntPtr lpNumberOfBytesRead);
        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, IntPtr lpSize, out IntPtr lpNumberOfBytesWritten);

        private Process hProcess = null;
        private ProcessModule hModule = null;
        private Hashtable addressPattern;

        public Memory(Process hProcess, ProcessModule hModule)
        {
            this.hProcess = hProcess;
            this.hModule = hModule;
            this.addressPattern = new Hashtable();
        }

        public Process getProcess()
        {
            return this.hProcess;
        }

        public int searchPattern(string pattern)
        {
            int address = -1;
            try
            {
                Match match;
                Regex regex = new Regex(pattern);
                int baseAddress = this.getBaseAddress();
                int moduleEndAddress = this.getModuleEndAddress();
                int currentAddress = baseAddress;
                do
                {
                    byte[] buffer = this.readBytes(currentAddress, 200000);
                    string opcode = BitConverter.ToString(buffer);
                    match = regex.Match(opcode);
                    if (match.Success)
                    {
                        break;
                    }
                    currentAddress += buffer.Length - ((pattern.Length + 1) / 3);
                }
                while (!match.Success & (currentAddress < moduleEndAddress));
                address = (int)Math.Round((double)((match.Index + 1) / 3) + currentAddress);
            }
            catch
            {
            }
            return address;
        }

        public int searchAddress(string prefix, string suffix)
        {
            int address = -1;
            try
            {
                Match match;
                string pattern = prefix + "-([0-9|A-F][0-9|A-F])-([0-9|A-F][0-9|A-F])-([0-9|A-F][0-9|A-F])-([0-9|A-F][0-9|A-F])-" + suffix;
                Regex regex = new Regex(pattern);
                int baseAddress = this.getBaseAddress();
                int moduleEndAddress = this.getModuleEndAddress();
                int currentAddress = baseAddress;
                do
                {
                    byte[] buffer = this.readBytes(currentAddress, 200000);
                    string opcode = BitConverter.ToString(buffer);
                    match = regex.Match(opcode);
                    if (match.Success)
                    {
                        break;
                    }
                    currentAddress += buffer.Length - ((pattern.Length + 1) / 3);
                } while (!match.Success & (currentAddress < moduleEndAddress));
                try {
                    address = int.Parse(match.Groups[4].ToString() + match.Groups[3].ToString() + match.Groups[2].ToString() + match.Groups[1].ToString(), NumberStyles.HexNumber);
                } catch {
                }
            }
            catch
            {
            }
            return address;
        }

        public int getBaseAddress()
        {
            return this.hModule.BaseAddress.ToInt32();
        }

        public int getModuleEndAddress()
        {
            return this.hModule.BaseAddress.ToInt32() + this.hModule.ModuleMemorySize;
        }

        public int readInt32(int address)
        {
            byte[] buffer = new byte[4];
            ReadProcessMemory(this.hProcess.Handle, (IntPtr)address, buffer, (IntPtr)buffer.Length, IntPtr.Zero);
            return BitConverter.ToInt32(buffer, 0);
        }

        public byte[] readBytes(int address, int length)
        {
            byte[] buffer = new byte[length];
            ReadProcessMemory(this.hProcess.Handle, (IntPtr)address, buffer, (IntPtr)buffer.Length, IntPtr.Zero);
            return buffer;
        }
    }
}
